// Typed Files (类型化文件) 示例
// 演示 Pascal 中类型化文件操作的各种用法
program p_24_typed_files;

{$mode objfpc}{$H+}
// {$mode objfpc} 启用 Object Pascal 模式
// {$H+} 启用长字符串支持（AnsiString）

// 引入单元文件
uses
  SysUtils;  // 系统工具单元，包含常用的系统函数

// 定义产品记录类型
type
  TProduct = record
    ID: Integer;
    Name: String[50];
    Price: Real;
    InStock: Boolean;
  end;

// 定义员工记录类型
type
  TEmployee = record
    EmpID: Integer;
    FirstName: String[30];
    LastName: String[30];
    Department: String[20];
    Salary: Real;
  end;

// 写入产品数据到类型化文件的过程
procedure WriteProductsToTypedFile(filename: String);
var
  fileVar: File of TProduct;
  products: array[1..4] of TProduct;
begin
  // 初始化产品数据
  products[1].ID := 1001;
  products[1].Name := '笔记本电脑';
  products[1].Price := 5999.99;
  products[1].InStock := True;
  
  products[2].ID := 1002;
  products[2].Name := '无线鼠标';
  products[2].Price := 199.99;
  products[2].InStock := True;
  
  products[3].ID := 1003;
  products[3].Name := '机械键盘';
  products[3].Price := 399.99;
  products[3].InStock := False;
  
  products[4].ID := 1004;
  products[4].Name := '显示器';
  products[4].Price := 1299.99;
  products[4].InStock := True;
  
  // 创建并打开类型化文件用于写入
  Assign(fileVar, filename);
  Rewrite(fileVar);
  
  // 写入产品数据
  for var i := 1 to 4 do
  begin
    Write(fileVar, products[i]);
    WriteLn('  写入产品记录 ID: ', products[i].ID, ' - ', products[i].Name);
  end;
  
  // 关闭文件
  Close(fileVar);
  WriteLn('  已将产品数据写入类型化文件: ', filename);
end;

// 顺序读取类型化文件中的产品数据
procedure ReadProductsFromTypedFile(filename: String);
var
  fileVar: File of TProduct;
  product: TProduct;
  recordNum: Integer = 1;
begin
  // 打开类型化文件用于读取
  Assign(fileVar, filename);
  Reset(fileVar);
  
  WriteLn('  顺序读取产品数据:');
  // 顺序读取产品数据
  while not Eof(fileVar) do
  begin
    Read(fileVar, product);
    WriteLn('    记录 ', recordNum, ':');
    WriteLn('      ID: ', product.ID);
    WriteLn('      名称: ', product.Name);
    WriteLn('      价格: ', product.Price:0:2);
    WriteLn('      有库存: ', product.InStock);
    Inc(recordNum);
  end;
  
  // 关闭文件
  Close(fileVar);
end;

// 随机访问类型化文件中的特定记录
procedure RandomAccessTypedFile(filename: String);
var
  fileVar: File of TProduct;
  product: TProduct;
begin
  // 打开类型化文件用于读取
  Assign(fileVar, filename);
  Reset(fileVar);
  
  WriteLn('  随机访问第3条记录:');
  
  // 定位到第3条记录（索引从0开始，所以是2）
  Seek(fileVar, 2);
  
  // 读取第3条记录
  if FilePos(fileVar) < FileSize(fileVar) then
  begin
    Read(fileVar, product);
    WriteLn('    ID: ', product.ID);
    WriteLn('    名称: ', product.Name);
    WriteLn('    价格: ', product.Price:0:2);
    WriteLn('    有库存: ', product.InStock);
  end
  else
    WriteLn('    文件中没有第3条记录');
  
  // 关闭文件
  Close(fileVar);
end;

// 演示文件指针操作
procedure DemonstrateFilePointer(filename: String);
var
  fileVar: File of TProduct;
  product: TProduct;
begin
  // 打开类型化文件用于读取
  Assign(fileVar, filename);
  Reset(fileVar);
  
  WriteLn('  演示文件指针操作:');
  WriteLn('    文件记录总数: ', FileSize(fileVar));
  
  // 移动到文件末尾
  Seek(fileVar, FileSize(fileVar));
  WriteLn('    当前文件指针位置: ', FilePos(fileVar));
  
  // 移动到文件开头
  Seek(fileVar, 0);
  WriteLn('    移动到开头后指针位置: ', FilePos(fileVar));
  
  // 读取第一条记录
  Read(fileVar, product);
  WriteLn('    读取第一条记录后指针位置: ', FilePos(fileVar));
  
  // 关闭文件
  Close(fileVar);
end;

// 写入和读取员工数据
procedure DemonstrateEmployeeRecords(filename: String);
var
  fileVar: File of TEmployee;
  employees: array[1..3] of TEmployee;
begin
  WriteLn('  演示员工记录操作:');
  
  // 初始化员工数据
  employees[1].EmpID := 101;
  employees[1].FirstName := '张';
  employees[1].LastName := '三';
  employees[1].Department := '开发部';
  employees[1].Salary := 8000.00;
  
  employees[2].EmpID := 102;
  employees[2].FirstName := '李';
  employees[2].LastName := '四';
  employees[2].Department := '测试部';
  employees[2].Salary := 6500.00;
  
  employees[3].EmpID := 103;
  employees[3].FirstName := '王';
  employees[3].LastName := '五';
  employees[3].Department := '产品部';
  employees[3].Salary := 7200.00;
  
  // 写入员工数据
  Assign(fileVar, filename);
  Rewrite(fileVar);
  for var i := 1 to 3 do
  begin
    Write(fileVar, employees[i]);
  end;
  Close(fileVar);
  WriteLn('    已写入员工数据到文件: ', filename);
  
  // 读取并显示员工数据
  Reset(fileVar);
  WriteLn('    员工信息:');
  while not Eof(fileVar) do
  begin
    var emp: TEmployee;
    Read(fileVar, emp);
    WriteLn('      ID: ', emp.EmpID, ', 姓名: ', emp.FirstName, emp.LastName,
            ', 部门: ', emp.Department, ', 薪资: ', emp.Salary:0:2);
  end;
  Close(fileVar);
end;

// 程序主入口
begin
  WriteLn('=== Pascal 类型化文件操作示例 ===');
  WriteLn;
  
  // 1. 创建并写入类型化文件
  WriteLn('1. 创建并写入类型化文件:');
  WriteProductsToTypedFile('products.dat');
  
  WriteLn;
  
  // 2. 顺序读取类型化文件
  WriteLn('2. 顺序读取类型化文件:');
  ReadProductsFromTypedFile('products.dat');
  
  WriteLn;
  
  // 3. 随机访问类型化文件
  WriteLn('3. 随机访问类型化文件:');
  RandomAccessTypedFile('products.dat');
  
  WriteLn;
  
  // 4. 文件指针操作
  WriteLn('4. 文件指针操作:');
  DemonstrateFilePointer('products.dat');
  
  WriteLn;
  
  // 5. 员工记录操作
  WriteLn('5. 员工记录操作:');
  DemonstrateEmployeeRecords('employees.dat');
  
  WriteLn;
  
  // 6. 清理 - 删除示例文件
  WriteLn('6. 清理:');
  var filesToDelete: array[1..2] of String = ('products.dat', 'employees.dat');
  for var i := 1 to 2 do
  begin
    if FileExists(filesToDelete[i]) then
    begin
      var fileVar: File of TProduct;  // 类型不重要，只要能删除文件即可
      Assign(fileVar, filesToDelete[i]);
      Erase(fileVar);
      WriteLn('  已删除文件: ', filesToDelete[i]);
    end;
  end;
  
  WriteLn;
  WriteLn('演示了 Pascal 中类型化文件操作的各种用法');
  
  // 等待用户按键，防止程序窗口立即关闭
  ReadLn;
end.